# 微程序控制器（生成器）
from cpu import pin
from cpu import asm as ASM
import os

# 指定当前目录，并设置生成的二进制微程序位micro.bin
my_dir = os.path.dirname(__file__)
filename = os.path.join(my_dir, 'micro.bin')
# 微程序
# 0x10000 = 2^5=32位数
LEN = 0X10000
micro = [pin.HLT for _ in range(LEN)]  # 初始化为停止

# 条件跳转指令集合
CONDITION_JMPS = {ASM.JO, ASM.JNO, ASM.JZ, ASM.JNZ, ASM.JP, ASM.JNP}

# 编译2地址指令
def compile_addr2(addr, ir, psw, index):
    global micro
    # ir 4位指令 | 2位目标数 | 2位源操作数
    op = ir & 0xf0  # 指令助记符
    amd = (ir >> 2) & 3  # 目标
    ams = ir & 3  # 源

    INST = ASM.INS_SUPPORT_LIST[2]
    # 指令不在支持的指令内，执行指令周期并返回
    if op not in INST:
        micro[addr] = pin.CYC
        return
    am = (amd,ams)
    if am not in INST[op]:
        micro[addr] = pin.CYC
        return
    # 拿到要执行的指令
    EXEC = INST[op][am]
    if index < len(EXEC):
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC

def get_condition_jump(EXEC, op, psw):
    # 溢出位
    overflow = psw & 1
    # 零位
    zero = psw & 2
    # 奇偶位
    parity = psw & 4

    if op == ASM.JO and overflow:
        return EXEC
    if op == ASM.JNO and not overflow:
        return EXEC
    if op == ASM.JZ and zero:
        return EXEC
    if op == ASM.JNZ and not zero:
        return EXEC
    if op == ASM.JP and parity:
        return EXEC
    if op == ASM.JNP and not parity:
        return EXEC
    return [pin.CYC]

# 获取中断指令，如果中断位允许则执行
def get_interrupt(EXEC, op, psw):
    intEn = psw & 8
    if intEn:
        return EXEC
    return [pin.CYC]

# 编译1地址指令
def compile_addr1(addr, ir, psw, index):
    # ir=1地址指令时 6位指令 | 2位目标数
    global micro
    global CONDITION_JMPS
    # ir 6位指令 | 2位目标操作数
    op = ir & 0xfc  # 指令助记符
    amd = ir & 3  # 目标操作数

    INST = ASM.INS_SUPPORT_LIST[1]
    # 指令不在支持的指令内，执行指令周期并返回
    if op not in INST:
        micro[addr] = pin.CYC
        return

    am = amd
    if am not in INST[op]:
        micro[addr] = pin.CYC
        return

    # 拿到要执行的指令
    EXEC = INST[op][am]
    # 如果指令是条件跳转指令，则获取跳转指令
    if op in CONDITION_JMPS:
        EXEC = get_condition_jump(EXEC, op, psw)
    # 如果是中断调用
    if op == ASM.INT:
        EXEC = get_interrupt(EXEC, op, psw)
    if index < len(EXEC):
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC
    pass

# 编译0地址指令
def compile_addr0(addr, ir, psw, index):
    global micro
    # ir=0地址指令时 8位指令
    op = ir

    INST = ASM.INS_SUPPORT_LIST[0]
    # 指令不在支持的指令内，执行指令周期并返回
    if op not in INST:
        micro[addr] = pin.CYC
        return

    # 拿到要执行的指令
    EXEC = INST[op]
    # print(f'exec = {EXEC}')
    if index < len(EXEC):
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC

# 处理指令
def do_compile():
    print("处理指令")
    for addr in range(LEN):
        # addr = 8位指令 + 4位psw + 4位cyc
        ir = addr >> 8
        psw = (addr >> 4) & 0xf
        cyc = addr & 0xf
        # 先处理ASM里的Fetch集合
        if cyc < len(ASM.FETCH):
            micro[addr] = ASM.FETCH[cyc]
            continue
        # ir = 1xxx xxxx
        addr2 = ir & (1 << 7)
        # ir = 01xx xxxx
        addr1 = ir & (1 << 6)

        index = cyc - len(ASM.FETCH)
        if addr2:
            # print(f'addr2 bin = {bin(addr)} , addr2 = {addr} , index = {index} , cyc= {cyc}')
            compile_addr2(addr, ir, psw, index)
        elif addr1:
            # print(f'addr1 = {addr} , index = {index} , cyc= {cyc}')
            compile_addr1(addr, ir, psw, index)
        else:
            # print(f'addr0 bin = {bin(addr)} , addr0 = {addr} , index = {index} , cyc= {cyc}')
            compile_addr0(addr, ir, psw, index)

    pass

# 发布微程序
def publish():
    # 处理指令
    do_compile()
    # 生成micro.bin
    with open(filename, 'wb') as file:
        for var in micro:
            byte = var.to_bytes(4, byteorder='little')  # 4字节小端，因为ROM的load需要小端格式
            file.write(byte)
    print("微程序生成成功!")
    pass


if __name__ == '__main__':
    # 发布微程序
    publish()
    pass
